package lambdasinaction.chap5.my;

import java.util.OptionalInt;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import lambdasinaction.chap4.MyDish;

/**
 * TODO
 *
 * @author Fish
 * @since 0.0.1 2018/7/25 16:47
 */
public class MyNumericStreams {

  public static void main(String[] args) {
    /**
     * 映射到数值流
     * 将流转换为特化版本的常用方法是mapToInt,mapToDouble和 mapToLong
     * 这些方法和前面说的map 方法的工作方式一样，只是它们返回的是一个特化流，而不是 Stream<T>
     * 例如，你可以像下面这样用mapToInt对 menu 中的卡路里求和
     * 这里，mapToInt会从每道菜中提取热量（用一个 Integer 表示），并返回一个 IntStream
     * 而不是一个Stream<Integer>.然后你就可以调用IntStream接口中定义的 sum 方法，对卡路里求和了。
     * 请注意，如果流是空的，sum 默认返回0.IntStream 还支持其他的方便方法，如 max、min、average 等
     */
    int calories = MyDish.menu.stream().mapToInt(MyDish::getCalories).sum();
    System.out.println("Number of calories:" + calories);

    /**
     * OptionalInt 原始类型特化版本
     * 例如，要找到IntStream 中的最大元素，可以调用 max 方法，它会返回一个 OptionalInt
     */
    OptionalInt maxCalories = MyDish.menu.stream().mapToInt(MyDish::getCalories).max();
    int max;
    if (maxCalories.isPresent()) {
      max = maxCalories.getAsInt();
    } else {
      max = 1;
    }
    System.out.println("max:" + max);

    /**
     * 数值范围
     * 和数字打交道时，有一个常用的东西就是数值范围。
     * 比如，假设你要生成1和100之间的所有数字
     * Java8引入了两个可以用于 IntStream和 LongStream的静态方法，帮助生成这种范围：
     * range和 rangeClosed。这两个方法都是第一个参数接受起始值，第二参数接受结束值。
     * 但 range 是不包含结束值的。而rangeClosed则包含结束值
     * 例如：
     * 表示范围[1, 100]
     * 一个从1到100的偶数流
     * 这里我们用了rangeClosed方法来生成1到100之间的所有数字。
     * 它会产生一个流，然后你可以链接 filter 方法，只选出偶数
     * 到目前为止还没有进行任何计算。最后，你对生成的流调用 count
     * 因为 count 是一个终端操作，所以它会处理流，并返回结果50，这正是1到100（包括两端）中所有偶数的个数
     * 请注意，比较一下，如果改用IntStream.range(1,100),则结果将会是49个偶数，因为 range是不包含结束值的
     */
    IntStream evenNumbers = IntStream.rangeClosed(1, 100).filter(n -> n % 2 == 0);
    System.out.println("从1到100有" + evenNumbers.count() + "个偶数");

    /**
     * 数值流应用：勾股数，直角三角形的三条边长
     * 勾股定理（毕达哥拉斯定理）
     *
     */
    Stream<int[]> pythagoreanTriples =
        IntStream.rangeClosed(1, 100).boxed()
            .flatMap(a -> IntStream.rangeClosed(a, 100)
                .filter(b -> Math.sqrt(a * a + b * b) % 1 == 0).boxed().map(b -> new int[]{a, b, (int)Math.sqrt(a*a + b*b)}));
    pythagoreanTriples.forEach(t -> System.out.println(t[0] + "," + t[1] + "," + t[2]));



  }

}
